//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using System;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Xml.Serialization;
namespace LargoCommon.Music
{
/// Real harmonic state.
/// Harmonic state represents relations in one real harmonic cluster
/// and enable to Compute its characteristics (continuity, impulse,..).
[Serializable]
[XmlRoot]
public sealed class HarmonicStateReal : HarmonicTransfer {
#region Fields
/// List of tones.
private readonly MusicalToneCollection toneList;
#endregion
#region Constructors
/// Initializes a new instance of the HarmonicStateReal class. Serializable.
public HarmonicStateReal() {
}
/// Initializes a new instance of the HarmonicStateReal class.
/// Harmonic system.
/// List of melodic tones.
public HarmonicStateReal(HarmonicSystem harmonicSystem, MusicalToneCollection toneArray)
: base(harmonicSystem) {
Contract.Requires(harmonicSystem != null);
Contract.Requires(toneArray != null);
//// if (toneArray == null) { return; }
this.toneList = toneArray;
if (this.toneList.Count > 1) {
byte idx = 0;
//// string tmpStr = string.Empty;
foreach (var mt in this.ToneList) {
mt.ToneIndex = idx++;
//// tmpStr += MusicalTone.GetNoteName(mt.Pitch.Element) + mt.Pitch.Octave;
}
//// HarmonicStateReal.LocalTemporaryProtocol += tmpStr + "\r\n";
this.AddAllIntervals();
}
this.SetRealProperties();
}
/// Initializes a new instance of the HarmonicStateReal class.
/// Harmonic system.
/// List of melodic tones.
/// Melodic tone.
public HarmonicStateReal(HarmonicSystem harmonicSystem, MusicalToneCollection toneArray, MusicalTone givenTone)
: base(harmonicSystem) {
Contract.Requires(harmonicSystem != null);
Contract.Requires(givenTone != null);
Contract.Requires(toneArray != null);
//// if (toneArray == null) { return; }
this.toneList = toneArray;
if (this.toneList.Count > 1) {
byte idx = 0;
foreach (var mt in this.ToneList) {
mt.ToneIndex = idx++;
}
}
this.AddIntervalsLeadingToTone(givenTone);
this.SetRealProperties();
}
///
/// Initializes a new instance of the HarmonicStateReal class.
///
/// The given system.
public HarmonicStateReal(HarmonicSystem givenSystem)
: base(givenSystem) {
Contract.Requires(givenSystem != null);
}
#endregion
#region Properties
//// Leads to out of memory exception
//// public static Dictionary UsedStates = new Dictionary();
/// Gets the property.
/// Property description.
public float RealContinuity { get; private set; }
/// Gets the property.
/// Property description.
public float RealImpulse { get; private set; }
/// Gets the property.
/// Property description.
public float RealPotential { get; private set; }
/// Gets the property.
/// Property description.
public float RealConsonance { get; private set; }
/// Gets list of tones.
/// Property description.
[XmlIgnore]
public MusicalToneCollection ToneList {
get {
Contract.Ensures(Contract.Result() != null);
if (this.toneList == null) {
throw new InvalidOperationException("List of tones is null.");
}
return this.toneList;
}
}
#endregion
#region Public static methods
/// Returns root values of elements in the structure.
/// Harmonic cluster.
/// Returns value.
public static Collection RootValues(HarmonicCluster harmonicCluster) {
Contract.Requires(harmonicCluster != null);
//// if (harmonicCluster == null) { return null; }
var hS = harmonicCluster.HarmonicSystem;
var values = new Collection();
foreach (var rcontinuity in from mt in harmonicCluster.ToneList
where mt != null
let mts = harmonicCluster.ToneList
select new HarmonicStateReal(hS, mts, mt)
into state
select state.MeanValueOfProperty(GenProperty.RealContinuity, false, true))
{
values.Add(rcontinuity);
}
return values;
}
/// Returns principal values of elements in the structure.
/// Harmonic cluster.
/// Returns value.
public static Collection PrincipalValues(HarmonicCluster harmonicCluster) {
Contract.Requires(harmonicCluster != null);
//// if (harmonicCluster == null) { return null; }
var hS = harmonicCluster.HarmonicSystem;
var values = new Collection();
foreach (var rcontinuity in from mt in harmonicCluster.ToneList
where mt != null
let mts = harmonicCluster.ToneList
select new HarmonicStateReal(hS, mts, mt)
into state
select state.MeanValueOfProperty(GenProperty.RealContinuity, true, true))
{
values.Add(rcontinuity);
}
return values;
}
#endregion
#region Public methods
/// Adds to the given array real intervals to given tone.
/// Melodic tone.
public void AddIntervalsLeadingToTone(MusicalTone toTone) {
Contract.Requires(toTone != null);
//// if (toTone == null) { return; }
//// const bool ignoreLongIntervals = true;
//// this.HarmonicSystem.GetRealInterval(fromTone.Pitch.SystemAltitude, toTone.Pitch.IntervalFrom(fromTone.Pitch));
//// if (toTone.Pitch == null) { return; }
var harmonicSystem = this.HarmonicSystem;
int toneIndex = toTone.ToneIndex;
//// 2011/11 - interval with two equal tones ignored
var toneAltitude = toTone.Pitch.SystemAltitude;
foreach (var interval in from fromTone in this.ToneList
where fromTone != null && fromTone.ToneIndex != toneIndex
&& fromTone.Pitch != null && fromTone.Pitch.SystemAltitude != toneAltitude
select new MusicalInterval(harmonicSystem, fromTone, toTone))
{
this.Intervals.Add(interval);
}
}
/// Sets harmonic properties of the cluster.
public void SetRealProperties() {
switch (this.Intervals.Count)
{
case 0:
return;
case 1:
this.SetRealPropertiesOfSingleTone();
return;
}
// float Level = (float)(Math.Sqrt(1+8*intervals.Count)+1)/2;
var rcontinuity = this.MeanValueOfProperty(GenProperty.RealContinuity, true, true);
var rimpulse = this.MeanValueOfProperty(GenProperty.RealImpulse, true, true);
var rsonance = HarmonicSystem.Consonance(rcontinuity, rimpulse);
this.RealContinuity = rcontinuity;
this.RealImpulse = rimpulse;
this.RealPotential = 0f;
this.RealConsonance = rsonance;
}
/// Sets harmonic properties of the cluster.
public void SetRealPropertiesOfSingleTone() {
this.RealContinuity = 0f;
this.RealImpulse = 0f;
this.RealPotential = 0f;
this.RealConsonance = 0f;
}
#endregion
#region Private methods
/// Makes array of intervals between tones of the cluster.
private void AddAllIntervals()
{
foreach (var mt in this.ToneList.Where(mt => mt?.Pitch != null))
{
this.AddIntervalsLeadingToTone(mt);
}
}
#endregion
}
}